package com.cskaoyan.wordmemorize.common;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cskaoyan.wordmemorize.dao.entity.VocBookDO;
import com.cskaoyan.wordmemorize.dao.entity.VocChapterDO;
import com.cskaoyan.wordmemorize.dao.mapper.VocBookMapper;
import com.cskaoyan.wordmemorize.dao.mapper.VocChapterMapper;
import com.cskaoyan.wordmemorize.dto.admin.VocExcelDTO;
import com.cskaoyan.wordmemorize.request.ExampleSentenceCommand;
import com.cskaoyan.wordmemorize.request.VocChapBookCommand;
import com.cskaoyan.wordmemorize.request.VocCommand;
import com.cskaoyan.wordmemorize.request.VocMeaningCommand;
import com.cskaoyan.wordmemorize.service.VocService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class MyReadListener implements ReadListener<VocExcelDTO> {
    /**
     * 每100条数据处理一次，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 100;
    /**
     * 缓存的数据
     */
    private List<VocExcelDTO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    /**
     * 假设这个是一个Mapper，当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private VocService vocService;
    private VocBookMapper vocBookMapper;
    private VocChapterMapper vocChapterMapper;


    private int totalCount = 0;
    private int successCount = 0;
    private int failCount = 0;
    private final List<FailRecord> failRecords = new ArrayList<>();

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param vocService
     */
    public MyReadListener(VocService vocService,VocBookMapper vocBookMapper,VocChapterMapper vocChapterMapper) {
        this.vocService = vocService;
        this.vocBookMapper = vocBookMapper;
        this.vocChapterMapper = vocChapterMapper;
    }

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(VocExcelDTO data, AnalysisContext context) {
        log.info("解析到一条数据:{}", JSON.toJSONString(data));
        cachedDataList.add(data);
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveBatch();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {

        if (!cachedDataList.isEmpty()) {
            saveBatch();
        }
        log.info("Excel导入完成，总计: {}, 成功: {}, 失败: {}",
                totalCount, successCount, failCount);
    }

    /**
     * 加上存储数据库
     */
    private void saveBatch() {
        if (cachedDataList.isEmpty()) {
            return;
        }

        try {
            // 转换为VocCommand列表
            List<VocCommand> commands = cachedDataList.stream()
                    .map(this::convertToVocCommand)
                    .collect(Collectors.toList());

            // 批量保存
            for (VocCommand command : commands) {
                vocService.addVoc(command);
            }
            successCount += cachedDataList.size();

            log.info("成功批量存储 {} 条数据", cachedDataList.size());
        } catch (Exception e) {
            // 批量失败转为单条处理
            log.error("批量存储失败，转为单条处理", e);
            for (VocExcelDTO data : cachedDataList) {
                try {
                    VocCommand command = convertToVocCommand(data);
                    vocService.addVoc(command);
                    successCount++;
                } catch (Exception ex) {
                    failCount++;
                    failRecords.add(new FailRecord(data.toString(), ex.getMessage()));
                    log.error("单条存储失败: {}", data, ex);
                }
            }
        }
    }
    // 统计信息获取方法
    public int getTotalCount() {
        return totalCount;
    }

    public int getSuccessCount() {
        return successCount;
    }

    public int getFailCount() {
        return failCount;
    }

    public List<FailRecord> getFailRecords() {
        return failRecords;
    }

    @Data
    @AllArgsConstructor
    public static class FailRecord {
        private String data;
        private String error;
    }

    public VocCommand convertToVocCommand(VocExcelDTO dto) {
        VocCommand command = new VocCommand();
        // 设置基本属性
        command.setContent(dto.getContent());
        command.setUkPhonetic(dto.getUkPhonetic());
        command.setUsPhonetic(dto.getUsPhonetic());
        command.setUkPronounciation(dto.getUkPronounciation());
        command.setUsPronounciation(dto.getUsPronounciation());

        // 解析并设置释义列表
        command.setInterpretations(parseInterpretations(dto.getInterpretations()));

        // 解析并设置例句列表
        command.setExamples(parseExamples(dto.getExampleSentences()));

        // 解析并设置关联关系
        command.setRelations(parseRelations(dto.getBookInfos()));

        return command;
    }

    // 解析多行释义
    private List<VocMeaningCommand> parseInterpretations(String interpretationsStr) {
        List<VocMeaningCommand> interpretations = new ArrayList<>();

        if (StringUtils.isBlank(interpretationsStr)) {
            return interpretations;
        }

        String[] lines = interpretationsStr.split("\n");
        for (String line : lines) {
            if (StringUtils.isBlank(line)) {
                continue;
            }

            VocMeaningCommand dto = new VocMeaningCommand();

            // 解析词性和释义内容（格式："词性. 释义内容"）
            int dotIndex = line.indexOf('.');
            if (dotIndex > 0) {
                dto.setType(line.substring(0, dotIndex + 1).trim());
                dto.setInterContent(line.substring(dotIndex + 1).trim());
            } else {
                dto.setType("");
                dto.setInterContent(line.trim());
            }

            interpretations.add(dto);
        }

        return interpretations;
    }


    /**
     * 解析例句和翻译
     */
    private List<ExampleSentenceCommand> parseExamples(String examplesStr) {
        List<ExampleSentenceCommand> examples = new ArrayList<>();

        if (StringUtils.isBlank(examplesStr)) {
            return examples;
        }

        String[] lines = examplesStr.split("\n");
        for (int i = 0; i < lines.length; i += 2) {
            if (StringUtils.isBlank(lines[i])) {
                continue;
            }

            ExampleSentenceCommand dto = new ExampleSentenceCommand();
            dto.setContent(lines[i].trim());

            // 如果有对应的翻译（下一行）
            if (i + 1 < lines.length && StringUtils.isNotBlank(lines[i + 1])) {
                dto.setMeaning(lines[i + 1].trim());
            } else {
                dto.setMeaning("");
            }

            examples.add(dto);
        }

        return examples;
    }

    private List<VocChapBookCommand> parseRelations(String bookInfosStr) {
        List<VocChapBookCommand> relations = new ArrayList<>();

        if (StringUtils.isBlank(bookInfosStr)) {
            return relations;
        }

        // 格式：书籍名称#章节名称
        String[] parts = bookInfosStr.split("#");
        if (parts.length >= 1) {
            VocChapBookCommand dto = new VocChapBookCommand();

            // 设置书籍名称
            if (parts.length > 0) {
                VocBookDO vocBookDO = vocBookMapper.selectOne(new LambdaQueryWrapper<VocBookDO>()
                        .eq(VocBookDO::getName, parts[0].trim()));
                dto.setBookId(String.valueOf(vocBookDO.getId()));
                dto.setBookName(parts[0].trim());
            }

            // 设置章节名称
            if (parts.length > 1) {
                VocChapterDO vocChapterDO = vocChapterMapper.selectOne(new LambdaQueryWrapper<VocChapterDO>()
                        .eq(VocChapterDO::getBookName, parts[0].trim())
                        .eq(VocChapterDO::getChapterName, parts[1].trim()));
                dto.setChapterId(String.valueOf(vocChapterDO.getId()));
                dto.setChapterName(parts[1].trim());
            }

            relations.add(dto);
        }

        return relations;
    }
}